#pragma once

#include <iostream>
#include <string>
#include <atomic>
#include <fstream>
#include <vector>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <boost/algorithm/string.hpp>

namespace ns_Util
{
    static std::string temp_path = "./temp/";

    class TimeUtil
    {
    public:
        static std::string GetTimeStamp()
        {
            struct timeval _time;
            gettimeofday(&_time, nullptr);
            // 这里需要返回字符串
            return std::to_string(_time.tv_sec);
        }
        static std::string GetTimeMs()
        {
            struct timeval _time;
            gettimeofday(&_time, nullptr);
            // tv_sec（秒）：从1970年1月1日起的秒数
            // tv_usec（微秒）：当前秒内的微秒数（范围 0 ~ 999,999）
            return std::to_string(_time.tv_sec * 1000 + _time.tv_usec / 1000);
        }
    };
    class PathUtil
    {
    public:
        static std::string AddSuffix(const std::string &file_name, std::string suffix)
        {
            // 字符串拼接
            std::string path_name = temp_path;
            path_name += file_name;
            path_name += suffix;

            return path_name;
        }
        // file_name + ".cpp"
        static std::string Sre(const std::string &File_name)
        {
            return AddSuffix(File_name, ".cpp");
        }
        // file_name + ".exe"
        static std::string Exe(const std::string &File_name)
        {
            return AddSuffix(File_name, ".exe");
        }
        static std::string CompilerError(const std::string &File_name)
        {
            return AddSuffix(File_name, ".compiler_error");
        }

        // 运行时需要的临时文件
        static std::string Stdin(const std::string &File_name)
        {
            return AddSuffix(File_name, ".stdin");
        }
        static std::string Stdout(const std::string &File_name)
        {
            return AddSuffix(File_name, ".stdout");
        }
        // file_name + ".err"
        static std::string Stderr(const std::string &File_name)
        {
            return AddSuffix(File_name, ".stderr");
        }
    };

    class FileUtil
    {
    public:
        static bool isFileExist(const std::string &path_name)
        {
            struct stat st;
            // 使用stat函数
            if (stat(path_name.c_str(), &st) == 0)
            {
                // 获取属性成功说明文件已经存在
                return true;
            }
            return false;
        }
        static std::string UniqFileName()
        {
            static std::atomic_uint id(0);
            id++;
            std::string uniq_id = std::to_string(id);
            std::string ms = TimeUtil::GetTimeMs();

            return ms + "_" + uniq_id;
        }
        static bool WriteFile(const std::string &target, std::string &content)
        {
            std::ofstream out(target);
            if(!out.is_open())
                return false;
            out.write(content.c_str(), content.size());
            out.close();

            return true;
        }
        static bool ReadFile(const std::string &target, std::string *content, bool keep = false)
        {
            //清空content
            (*content).clear();

            std::ifstream in(target);
            if(!in.is_open())
                return false;
            std::string line;
            //注意: 1、getline不保存行分隔符，但是有些情况我们需要行分隔符
            //      2、getline内部重载了强制类型转化
            while(getline(in, line))
            {
                (*content) += line;
                //若keep为true，加\n
                (*content) += (keep ? "\n" : " ");
            }
            in.close();

            return true;
        }
    };

    class StringUtil
    {
    public:
        //切割字符串函数
        static void SplitString(std::string &line, std::vector<std::string> *target, std::string &sep)
        {   
            //最后一个参数指的是：是否需要被压缩
            //例子： 1    题目 难度 cpu mem 
            //"1"和"题目"之间有很多空格,选择被压缩(也就是on) 得出的结果则是
            //1
            //题目
            //难度
            //cpu
            //mem
            //反之则是保留他们之间的空格
            boost::split((*target), line, boost::is_any_of(sep), boost::token_compress_on);
        }
    };
}